#include <iostream>
#include <functional>  // 用于std::function和std::bind
#include <memory>      // 用于智能指针
#include <thread>      // 多线程支持
#include <future>      // 异步任务和future
#include <mutex>       // 互斥锁
#include <condition_variable> // 条件变量
#include <vector>      // 容器

// 线程池类
class threadpool 
{
public:
    using Functor = std::function<void(void)>; // 定义任务类型为无参数无返回的函数对象

    // 构造函数，创建thr_count个工作线程
    threadpool(int thr_count = 1) : _stop(false) 
    {
        for (int i = 0; i < thr_count; i++) 
        {
            _threads.emplace_back(&threadpool::entry, this); // 创建线程并指定入口函数
        }
    }

    // 析构函数，自动停止线程池
    ~threadpool() 
    {
        stop();
    }

    // 停止线程池，等待所有线程结束
    void stop() 
    {
        if (_stop == true) return;
        _stop = true;                // 设置停止标志
        _cv.notify_all();            // 唤醒所有等待的线程
        for (auto &thread : _threads) 
        {
            thread.join();           // 等待线程结束
        }
    }

    // 将任务添加到线程池，并返回一个future以获取结果
    template<typename F, typename ...Args>
    auto push(const F &&func, Args&& ...args) -> std::future<decltype(func(args...))> 
    {
        // 1. 将传入的函数封装成一个packaged_task任务
        using return_type = decltype(func(args...)); // 推导返回类型

        // 使用bind绑定函数和参数，完美转发以保持参数类型
        auto tmp_func = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
        
        // 创建packaged_task，用shared_ptr管理以便lambda捕获
        auto task = std::make_shared<std::packaged_task<return_type()>>(tmp_func);
        std::future<return_type> fu = task->get_future(); // 获取关联的future
        // 2. 构造一个lambda匿名函数（捕获任务对象），函数内执行任务对象
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 将任务封装成无参数的lambda，加入任务池
            _taskpool.push_back([task](){ (*task)(); });
            _cv.notify_one(); // 通知一个等待的线程
        }
        return fu; // 返回future，供调用者获取结果
    }

private:
    // 工作线程的入口函数
    void entry() 
    {
        while (!_stop) 
        {
            std::vector<Functor> tmp_taskpool;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                // 等待条件：线程池停止或任务池非空
                _cv.wait(lock, [this](){ return _stop || !_taskpool.empty(); });
                
                // 交换任务到临时容器，减少锁的持有时间
                tmp_taskpool.swap(_taskpool);
            }
            // 执行所有任务
            for (auto &task : tmp_taskpool) 
            {
                task();
            }
        }
    }

private:
    std::atomic<bool> _stop;                     // 停止标志
    std::vector<Functor> _taskpool;              // 任务队列
    std::mutex _mutex;                           // 保护任务队列的互斥锁
    std::condition_variable _cv;                 // 条件变量，用于任务通知
    std::vector<std::thread> _threads;           // 工作线程集合
};

// 示例函数：两数相加
int Add(int num1, int num2) 
{
    return num1 + num2;
}

int main() 
{
    threadpool pool; // 创建线程池，默认1个线程
    for (int i = 0; i < 10; i++) 
    {
        // 提交任务到线程池，并获取future
        std::future<int> fu = pool.push(Add, 11, i);
        // 等待任务完成并输出结果
        std::cout << fu.get() << std::endl;
    }
    pool.stop(); // 显式停止线程池（析构时也会自动停止）
    return 0;
}